-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
API for traversing Relationships and RelationshipTargets in dynamic contexts
#21601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API for traversing Relationships and RelationshipTargets in dynamic contexts
#21601
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like this feature and already see me using this. 👍
|
This looks good! I see I'm too late to give an official approval, but I still wanted to leave a few thoughts: Will we want the Given how few components are relationships, would we want to do something like |
I've thought about adding that, but that'll require initializing this field after creating the
Yeah, that makes sense. Ideally we'd have components-as-entities so that @urben1680 also mentioned that a flag indicating whether there is any other data besides |
Oh, right, there are links in both directions, so you can't just register one component first and then pass it to the other. Yeah, that's harder than I thought!
The reason it's on my mind is that I'm trying to figure out how to safely allow mutable query access through |
Because we can't trust that |
…ic contexts (bevyengine#21601) # Objective Currently there is no way to traverse relationships in type-erased contexts or to define dynamic relationship components, which is a hole in the current relationships api. ## Solution Introduce `RelationshipAccessor` to describe a way to get `Entity` values from any registered relationships in dynamic contexts and store it on `ComponentDescriptor`. This allows to traverse relationships without knowing their type, which is useful for working with entity hierarchies using non-default components. ## Testing Added a simple test/example of how to use this api to traverse hierarchies in a type-erased context.
| // - offset is in bounds, aligned and has the same lifetime as the original pointer. | ||
| // - value at offset is guaranteed to be a valid Entity | ||
| let child_of_entity: Entity = | ||
| unsafe { *child_of_ptr.byte_add(*entity_field_offset).deref() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should a helper method be provided to do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There could be, but I'm not sure how it would look like since it's an enum. I guess we can add RelationshipAccessor::get_relationship_entity(relationship_component: Ptr<'_>) -> Option<Entity>, but I'm not sure if it's any more ergonomic than matching.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I've started using the API to dynamically traverse relations in multi-source queries and I was tripped by the fact that is an enum. I think it might be better to split it into 2 separate structs?
Or maybe this would be resolved if we had
Also maybe we could have some more user friendly wrappers like:
UnsafeEntityCell.get_relationship_by_id(relationship_id) which would under the hood fetch the correct RelationshipAccessor.
So that we could do world.get(source)?.get_relationship_by_id(relationship_id)?
I can try adding that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RelationshipAccessor could have a mapper method that returns this enum:
enum RelationshipAccessorDeref<'a> {
Relationship {
entity: Entity,
linked_spawn: bool,
},
RelationshipTarget {
iter: Box<dyn Iterator<Item = Entity> + 'a>,
linked_spawn: bool,
}
}The mapper needs to be unsafe though with notice that RelationshipAccessor must originate from ComponentInfo or constructed with the given unsafe constructor.
Objective
Currently there is no way to traverse relationships in type-erased contexts or to define dynamic relationship components, which is a hole in the current relationships api.
Solution
Introduce
RelationshipAccessorto describe a way to getEntityvalues from any registered relationships in dynamic contexts and store it onComponentDescriptor. This allows to traverse relationships without knowing their type, which is useful for working with entity hierarchies using non-default components.Testing
Added a simple test/example of how to use this api to traverse hierarchies in a type-erased context.